﻿' ------------------------------------------------------------------------------
' The UpdateGrid() method displays a DataTable in a DataGridView
' control.
'
' Most columns are displayed as text using the default symbology. The
' following columns are treated specially:
'
'     Image (filestream)
'         - colored green, displayed as text "Byte[] Array"
'     TinyThumbnail
'         - displayed as image, moved to first column, no caption
'           in the column header
'     Thumbnail
'         - turned off
'     DateTimeOffset
'         - colored blue
'     spatial columns Location, ZonePolygon
'         - colored violet-red
'     sparse columns (per MetaSpecs, not actual definition) 
'         - colored peachpuff
'
' The method creates the columns instead of letting the the control do
' automatically because of performance issues when the control scans
' the Image (filestream) column to determine the type of data held in
' the binary data. The control correctly determines the Image column
' contains images, but this takes a long time, and the control cannot
' display the images and do them justice in any case.
'
' In order to display null values distinctively, each
' DataGridViewControl used in the application forwards the
' CellFormatting events to the CellFormatting method in this module. The
' client passes in a dictionary that contains the cell styles for null
' cells so they can be reused instead of being created each time a cell
' is rendered.
'
' Similarly, each DataGridViewControl's handler for the OnDataError
' event is routed to the OnDataError() method. These errors are handled
' by doing nothing, leaving the display unchanged and the user
' untroubled.
' ------------------------------------------------------------------------------
' This file is part of the SQL Server 2008 Technology Demonstration. This
' application was designed and coded by Eric Weitzman, LandTime Inc, for
' Microsoft Corporation. Contact Ed Katibah at Microsoft about this demo.
' Copyright © 2008 Microsoft Corporation. All rights reserved.
' ------------------------------------------------------------------------------

Module DataGridUtils

    Public Class CellStyleDictionary
        Inherits Dictionary(Of Integer, DataGridViewCellStyle)
    End Class

    Public Sub UpdateGrid(ByVal dgv As DataGridView, ByVal source As DataTable, ByVal largeview As Boolean)

        ReportingUtils.StartTimer()

        dgv.SuspendLayout()
        AddHandler dgv.DataError, AddressOf OnDataError

        Dim columns As DataGridViewColumnCollection
        columns = dgv.Columns
        columns.Clear()

        dgv.AutoGenerateColumns = False
        dgv.DataSource = source

        For Each dc As DataColumn In source.Columns
            Dim dgc As DataGridViewColumn
            Dim colname As String = dc.ColumnName
            If colname = "TinyThumbnail" Then
                dgc = New DataGridViewImageColumn
            Else
                dgc = New DataGridViewTextBoxColumn
            End If
            dgc.Name = colname
            dgc.HeaderText = colname
            dgc.DataPropertyName = colname
            columns.Add(dgc)
        Next

        dgv.RowHeadersVisible = True
        dgv.RowHeadersWidth = 20
        Dim index As Integer

        Dim oldcol As DataGridViewColumn = dgv.Columns.Item(Schema.ImageFilestreamColumn)
        If oldcol IsNot Nothing Then
            index = dgv.Columns.IndexOf(oldcol)
            dgv.Columns.Remove(oldcol)
            Dim imagecol As New DataGridViewTextBoxColumn()
            imagecol.Name = "Image"
            imagecol.HeaderText = "Image"
            imagecol.DataPropertyName = "Image"
            imagecol.DefaultCellStyle.BackColor = Color.PaleGreen
            dgv.Columns.Insert(index, imagecol)
        End If

        Dim col As DataGridViewColumn
        col = dgv.Columns.Item(Schema.ImageFilestreamColumnDotPathName)
        If col IsNot Nothing Then
            col.Name = Schema.ImageFilestreamColumn
            col.HeaderText = Schema.ImageFilestreamColumn
            col.DefaultCellStyle.BackColor = Color.PaleGreen
        End If

        ' hide these columns

        col = dgv.Columns.Item("Thumbnail") : If col IsNot Nothing Then col.Visible = False
        'col = dgv.Columns.Item(My.Settings.COLUMN_PhotoImageFilestream) : If col IsNot Nothing Then col.Visible = False
        'col = dgv.Columns.Item("TinyThumbnail") : If col IsNot Nothing Then col.Visible = False

        ' custom colors

        col = dgv.Columns.Item("DateTimeOffset") : If col IsNot Nothing Then col.DefaultCellStyle.BackColor = Color.SkyBlue
        col = dgv.Columns.Item("Location") : If col IsNot Nothing Then col.DefaultCellStyle.BackColor = Color.PaleVioletRed
        col = dgv.Columns.Item("ZonePolygon") : If col IsNot Nothing Then col.DefaultCellStyle.BackColor = Color.PaleVioletRed


        ' color the sparse columns

        For Each spec As MetaSpec In ExifMetadata.MetaMapper.MetaSpecs.Values
            If spec.IsSparse Then
                Try
                    Dim c As DataGridViewColumn = dgv.Columns.Item(spec.ColumnName)
                    c.DefaultCellStyle.BackColor = Color.PeachPuff
                Catch : End Try
            End If
        Next

        ' this causes the data to be loaded into the grid, so do things that this might afterwards

        dgv.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells)

        ' move & resize the TinyThumbnail column

        col = dgv.Columns.Item("TinyThumbnail")
        If col IsNot Nothing Then
            index = dgv.Columns.IndexOf(col)
            dgv.Columns.Remove(col)
            dgv.Columns.Insert(0, col)
            col.Width = 30
            col.HeaderText = ""
            index = dgv.Columns.IndexOf(col)
        End If

        dgv.ResumeLayout()
        ReportingUtils.ShowTimer("update datagrid")

    End Sub

    Public Sub CellFormatting(ByVal dgv As DataGridView, ByVal nullstyles As CellStyleDictionary, _
                              ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs)

        Dim isnull As Boolean = False
        If TypeOf e.Value Is System.DBNull Then
            isnull = True
        ElseIf TypeOf e.Value Is Microsoft.SqlServer.Types.SqlGeography Then
            Dim g As Microsoft.SqlServer.Types.SqlGeography = CType(e.Value, Microsoft.SqlServer.Types.SqlGeography)
            isnull = g.IsNull
        ElseIf TypeOf e.Value Is Microsoft.SqlServer.Types.SqlGeometry Then
            Dim g As Microsoft.SqlServer.Types.SqlGeometry = CType(e.Value, Microsoft.SqlServer.Types.SqlGeometry)
            isnull = g.IsNull
        End If
        If Not isnull Then Return

        e.Value = "NULL"
        Dim i As Integer = e.ColumnIndex
        If nullstyles.ContainsKey(i) Then
            e.CellStyle = nullstyles.Item(i)
        Else
            Dim nullstyle As DataGridViewCellStyle = dgv.Columns.Item(i).DefaultCellStyle.Clone
            Static nullforecolor As Color = Color.FromArgb(255, 170, 170, 170)
            Static nullbackcolor As Color = Color.White
            nullstyle.ForeColor = nullforecolor
            If nullstyle.BackColor = Nothing Then nullstyle.BackColor = nullbackcolor
            nullstyle.Font = New Font(dgv.Font, FontStyle.Bold Or FontStyle.Italic)
            nullstyle.Alignment = DataGridViewContentAlignment.MiddleLeft
            nullstyles.Add(i, nullstyle)
            e.CellStyle = nullstyles(i)
        End If
        e.FormattingApplied = True
    End Sub

    Private Sub OnDataError(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewDataErrorEventArgs)
        ' ignore data errors
    End Sub

    Public Sub ClearGrid(ByVal dgv As DataGridView)
        dgv.SuspendLayout()
        dgv.DataSource = Nothing
        dgv.Columns.Clear()
        dgv.ResumeLayout()
    End Sub

End Module
